/******************************************************
* Team WB
* Brett Cate, William Kim
* 
* Memory Module ADT Source
*******************************************************/

#include "memoryModule.h"

/* 
Returns a byte from address.

parameter (mm): pointer to the memory module.
parameter (address): address to fetch byte from.
parameter (error): pointer to the int value for the error code of this function.

return value: the byte from the memory module at the given address.
*/
MemoryModulePtr memory_new() {
	MemoryModulePtr memoryModulePtr = (MemoryModulePtr) malloc(sizeof(uchar) * ADDRESS_SPACE);
	int i = 0;
	
	// initialize with random values
	for (i = 0; i < ADDRESS_SPACE; i++) {
		memoryModulePtr[i] = rand() / (RAND_MAX / MAX_UCHAR_VAL + 1);
	}
	
	return memoryModulePtr;

}

/*
Creates a new IO memory module of the given size and returns a pointer to the module.

parameter(the_size): Int value of the size of the memory module to be created.

return value: Pointer to the memory module created.
*/
MemoryModulePtr memory_newIOMemory(int the_size) {
	return (MemoryModulePtr) malloc(sizeof(uchar) * the_size);
}

/* 
Returns a byte from address.

parameter (mm): pointer to the memory module.
parameter (address): address to fetch byte from.
parameter (error): pointer to the int value for the error code of this function.

return value: the byte from the memory module at the given address.
*/
uchar memory_fetchByteFrom(MemoryModulePtr the_mm, ushort the_address, int* the_error) {
	if (the_mm == NULL) {
		*the_error = NULL_POINTER_ERROR;
		return 0;
	}

	*the_error = NO_ERROR;
	return the_mm[the_address - MEM_START];
}

/* 
Stores byte at address.

parameter (mm): pointer to the memory module.
parameter (address): address to store byte to.

return value: error code.
*/
int memory_storeByteTo(MemoryModulePtr the_mm, ushort the_address, uchar the_byte) {
	if (the_mm == NULL) {
		return NULL_POINTER_ERROR;
	}

	the_mm[the_address - MEM_START] = the_byte;
	return NO_ERROR;
}

/* 
Returns the contents of two consecutive locations starting at address.

parameter (mm): pointer to the memory module.
parameter (address): the starting address to fetch word from (big-endian)
parameter (error): pointer to the int value for the error code of this function.

return value: the word starting at the given address (big-endian).
*/
ushort memory_fetchWordFrom(MemoryModulePtr the_mm, ushort the_address, int * the_error) {
	ushort result = 0;

	if (the_mm == NULL) {
		*the_error = NULL_POINTER_ERROR;
		return 0;
	}
	if (the_address < MEM_START || the_address > MEM_END - 1) {
		*the_error = ADDRESS_OOB_ERROR;
		return 0;
	}

	*the_error = NO_ERROR;
	result = the_mm[the_address - MEM_START];
	result = result << 8;
	result = result | the_mm[the_address - MEM_START + 1];

	return result;
}

/* 
Stores the contents at two consecutive locations starting at address. 

parameter (mm): pointer to the memory module.
parameter (address): starting address to store word to (big-endian).

return value: error code.
*/
int memory_storeWordTo(MemoryModulePtr the_mm, ushort the_address, ushort the_word) {
	if (the_mm == NULL) {
		return NULL_POINTER_ERROR;
	}
	if (the_address < MEM_START || the_address > MEM_END - 1) {
		return ADDRESS_OOB_ERROR;
	}

	the_mm[the_address - MEM_START] = (uchar) (the_word >> 8);
	the_mm[the_address - MEM_START + 1] = (uchar) (the_word);
	return NO_ERROR;
}

/*
Returns the byte at the given address of the given IO memory module.

parameter(the_mm): The memory module.
parameter(the_address): The address.
parameter(the_error): Pointer to the error code value.

return value: The uchar value at the given address.
*/
uchar memory_IOFetchByteFrom(MemoryModulePtr the_mm, ushort the_address, int* the_error) {
	if (the_mm == NULL) {
		*the_error = NULL_POINTER_ERROR;
		return 0;
	}
	*the_error = NO_ERROR;
	return the_mm[the_address];
}

/*
Puts the given byte at the given address of the memory module.

parameter(the_mm): The memory module.
parameter(the_address): The address.
parameter(the_byte): The byte to put at the given address.

return value: The int value of the error code.
*/
int memory_IOStoreByteTo(MemoryModulePtr the_mm, ushort the_address, uchar the_byte) {
	if (the_mm == NULL) {
		return NULL_POINTER_ERROR;
	}

	the_mm[the_address] = the_byte;
	return NO_ERROR;
}

/* End Program */
